Skip to content

fix: graceful ENOENT error when DESIGN.md is missing (#132)#145

Merged
davideast merged 2 commits into
google-labs-code:mainfrom
Emp1500:fix/enoent-friendly-error
Jul 1, 2026
Merged

fix: graceful ENOENT error when DESIGN.md is missing (#132)#145
davideast merged 2 commits into
google-labs-code:mainfrom
Emp1500:fix/enoent-friendly-error

Conversation

@Emp1500

@Emp1500 Emp1500 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

fix(cli): graceful error on missing or unreadable input file

##Before
ERROR ENOENT: no such file or directory, open 'DESIGN.md'
at readFileSync (node:fs:441:20)
at readInput (...index.js:24123:12)

##After

File missing:
Error: "DESIGN.md" not found. Create a DESIGN.md file or pass "-" to read from stdin.

Permission denied:
Error: "DESIGN.md" could not be read: permission denied.

Any other I/O error:
Error: "DESIGN.md" could not be read:

##Solution

Introduces a typed FileReadError class. readInput now throws it instead of calling process.exit directly. A friendlyMessage getter on the class checks the underlying OS error code
(ENOENT, EACCES, etc.) to produce an accurate message — so the error never says "not found" when the real problem is permissions.

Each command catches FileReadError, writes the plain-text message to stderr, and exits with code 2.

##Why this approach is better than a plain process.exit wrap:

  • readInput is unit-testable without mocking process.exit
  • FileReadError.filePath pinpoints which file failed (matters for diff, which reads two files)
  • FileReadError.friendlyMessage centralises message logic in one place — commands stay clean
  • Exit-code policy stays in the command layer where it belongs

##Changes

  • utils.ts — FileReadError class with friendlyMessage getter + readInput throws instead of exits
  • utils.test.ts — 6 new tests for readInput and FileReadError, zero mocking required
  • commands/lint.ts, commands/diff.ts, commands/export.ts — catch FileReadError, write error.friendlyMessage to stderr, exit code 2

Fixes #132

Emp1500 added 2 commits June 28, 2026 04:14
… stderr (google-labs-code#132)

Introduce a typed `FileReadError` class in `readInput` so the function
throws instead of calling `process.exit` directly. Each command handler
catches it and writes a plain-text error to stderr:

  Error: "DESIGN.md" not found.
  Create a DESIGN.md file or pass "-" to read from stdin.

This replaces the unhandled Node.js stack trace dump reported in google-labs-code#132.
`readInput` is now unit-testable without mocking `process.exit`, and
`FileReadError.filePath` identifies the specific missing file (important
for `diff`, which reads two files).
Replace the hardcoded "not found" string in all command handlers with
a friendlyMessage getter on FileReadError that checks the OS error code:
- ENOENT → "not found. Create a DESIGN.md file or pass '-' for stdin."
- EACCES → "could not be read: permission denied."
- other  → "could not be read: <raw message>"

This prevents a misleading "not found" message when the file exists
but cannot be read due to permissions or other I/O errors.

@davideast davideast left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Emp1500!

@davideast davideast merged commit ab4876f into google-labs-code:main Jul 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ENOENT: no such file or directory error when DESIGN.md is missing

2 participants